﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage;

namespace G.Utils
{
    /// <summary>
    /// 文件内容的类型，主要是配合文件和对象互相序列化用的
    /// </summary>
    public enum FileContentType
    {
        XML,
        JSON
    }

    public static class APPFileHelp
    {
        /// <summary>
        /// 根据文件地址将文件内容转换成相应的泛型对象,如果文件不存在将会返回泛型的默认类型，比如是引用类型的，那么返回的是null
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fileName"></param>
        /// <param name="fileType"></param>
        /// <returns></returns>
        public static async Task<T> DeserializeObjectFromFile<T>(string fileName, FileContentType fileType = FileContentType.XML, bool isSecurity = false, string securityKey = null)
        {
            StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
            StorageFile file = null;
            T objTarget;
            try
            {
                file = await storageFolder.GetFileAsync(fileName);
            }
            catch (Exception)
            {
            }
            if (file == null)
            {
                objTarget = default(T);
            }
            else
            {
                try
                {
                    string str = await Decrypt(isSecurity, securityKey, file);
                    switch (fileType)
                    {
                        case FileContentType.XML:
                            objTarget = SerializerHelp.XMLDeserialize<T>(str);
                            break;
                        case FileContentType.JSON:
                            objTarget = SerializerHelp.JsonDeserialize<T>(str);
                            break;
                        default:
                            throw new ArgumentException("不支持该类型的FileContentType");
                    }
                }
                catch (Exception)
                {
                    objTarget = default(T);
                }
            }
            return objTarget;
        }

        private static async Task<string> Decrypt(bool isSecurity, string securityKey, StorageFile file)
        {
            string str = string.Empty;
            try
            {
                if (isSecurity)
                {
                    if (securityKey == null)
                        throw new Exception("缺少密钥");
                    BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
                    var buffer = await FileIO.ReadBufferAsync(file);
                    var dec = Windows.Security.Cryptography.SecurityExtention.SampleCipherDecryption(SymmetricAlgorithmNames.Rc2EcbPkcs7, buffer, securityKey, encoding);
                    str = CryptographicBuffer.ConvertBinaryToString(encoding, dec);
                }
                else
                    str = await FileIO.ReadTextAsync(file);
            }
            catch (Exception) { }
            return str;
        }


        public static async Task<object> DeserializeObjectFromFile(string fileName, Type type, FileContentType fileType = FileContentType.XML, bool isSecurity = false, string securityKey = null)
        {
            StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
            StorageFile file = null;
            object objTarget;
            try
            {
                file = await storageFolder.GetFileAsync(fileName);
            }
            catch (Exception)
            {

            }
            if (file == null)
            {
                objTarget = null;
            }
            else
            {
                string str = await Decrypt(isSecurity, securityKey, file);
                switch (fileType)
                {
                    case FileContentType.XML:
                        objTarget = SerializerHelp.XMLDeserialize(str, type);
                        break;
                    case FileContentType.JSON:
                        objTarget = SerializerHelp.JsonDeserialize(str, type);
                        break;
                    default:
                        throw new ArgumentException("不支持该类型的FileContentType");
                }
            }
            return objTarget;
        }

        /// <summary>
        /// 将某个对象序列化成文件，如果传递的对象为null，那么删除原来的文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="target"></param>
        /// <param name="fileType">文本内容类型</param>
        /// <param name="isSecurity">是否采用加密的方式保存文本</param>
        /// <param name="securityKey">密钥</param>
        /// <returns></returns>
        public static async Task SerializeObjectToFile(string fileName, object target, FileContentType fileType = FileContentType.XML, bool isSecurity = false, string securityKey = null)
        {
            StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
            StorageFile storageFile = null;
            //如果target为null，那么删除文件
            if (target == null)
            {
                storageFile = await storageFolder.GetFileAsync(fileName);
                if (storageFile != null)
                {
                    await storageFile.DeleteAsync();
                }
                return;
            }
            string str;
            switch (fileType)
            {
                case FileContentType.XML:
                    str = SerializerHelp.XmlSerializer(target);
                    break;
                case FileContentType.JSON:
                    str = SerializerHelp.JsonSerializer(target);
                    break;
                default:
                    throw new ArgumentException("不支持该类型的FileContentType");
            }
            storageFile = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
            if (isSecurity)
            {
                await Encryp(securityKey, storageFile, str);
            }
            else
                await FileIO.WriteTextAsync(storageFile, str);
        }
        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="securityKey"></param>
        /// <param name="storageFile"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        private static async Task Encryp(string securityKey, StorageFile storageFile, string str)
        {
            if (securityKey == null)
                throw new Exception("缺少密钥");
            BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
            Windows.Storage.Streams.IBuffer buffer = Windows.Security.Cryptography.SecurityExtention.SampleCipherEncryption(str, SymmetricAlgorithmNames.Rc2EcbPkcs7, securityKey, encoding);
            await FileIO.WriteBufferAsync(storageFile, buffer);
        }
    }
}
